<?php
class Users
{
	private static $_instance = null;
	private $_db = null;
	
	private function __construct()
	{
		$this->_db = Yii::app()->db;
		$this->_db->setAttribute(PDO::ATTR_CASE,PDO::CASE_LOWER);
	}
	
	public static function getInstance() 
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
	
	
	public function getList(array $args = array(), $intPage = 1, $intLimit = MIN_ROWS_PER_PAGE)
	{
		try{
			$defaults = array(
				'keyword' => null,
				'role_id' => null,
				'created_from' => null,
				'created_to' => null			
			);
			$args = array_merge($defaults, $args);
			
			$intStart = ($intPage-1)*$intLimit;
			
			$strRoleCond = '';
			if(!empty($args['role_id'])){
				$strRoleCond .= "INNER JOIN (SELECT user_id
											FROM tbl_users_roles
											WHERE role_id IN ( {$args['role_id']} )
								) ur ON u.user_id = ur.user_id";
			}
			
			$arrWhere = array();
			if(!empty($args['keyword'])){
				$arrWhere[] = "user_username LIKE \"%{$args['keyword']}%\" OR user_email LIKE \"%{$args['keyword']}%\"";
			}
			if(!empty($args['created_from'])){
				$args['created_from'] = date('Y-m-d', strtotime($args['created_from']));
				$arrWhere[] = "user_created_date >= '{$args['created_from']}'";
			}
			if(!empty($args['created_to'])){
				$args['created_to'] = date('Y-m-d', strtotime($args['created_to']));
				$arrWhere[] = "user_created_date <= '{$args['created_to']}'";
			}
			$strWhere = '';
			if(!empty($arrWhere)){
				$strWhere = 'WHERE '.implode(' AND ', $arrWhere);
			}
			
			$strSql = " SELECT SQL_CALC_FOUND_ROWS u.* 
						FROM tbl_users u
						{$strRoleCond}
						{$strWhere}
						LIMIT :intStart, :intLimit";
			
			$cmd = $this->_db->createCommand($strSql);
			$cmd->bindParam(":intStart",$intStart,PDO::PARAM_INT);
			$cmd->bindParam(":intLimit",$intLimit,PDO::PARAM_INT);
			
			$arrResults = $cmd->queryAll();
			if(!empty($arrResults)){
				$arrResults[0]['total_rows'] = $this->_db->createCommand('SELECT FOUND_ROWS();')->queryScalar();
			}
			return $arrResults;
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function getByUsername($id){
		if($id === null || $id == '') throw new Exception('Invalid username!');
		try{
			$strSQL = " SELECT u.*
						FROM tbl_users u
						WHERE u.user_username=:id OR u.user_email=:id";
			$cmd = $this->_db->createCommand($strSQL);
			$cmd->bindParam(":id",$id,PDO::PARAM_STR);
			return $arrResults = $cmd->queryRow();
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function get($id)
	{
		try{
			$strSQL = " SELECT u.*
						FROM tbl_users u
						WHERE u.user_id=:id";
			$cmd = $this->_db->createCommand($strSQL);
			$cmd->bindParam(":id",$id,PDO::PARAM_STR);
			return $arrResults = $cmd->queryRow();
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function insert(array $args)
	{		
		try{
			$defaults = array(
				'site_id' => SITE,
				'user_username' => null,
				'user_email' => null,
				'user_fullname' => null,
				'user_password' => null			
			);
			$args = array_merge($defaults, $args);
			
			$cmd = $this->_db->createCommand();
			$cmd->insert('tbl_users',$args);
			return Yii::app()->db->getLastInsertId();
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function update($id, array $args)
	{		
		try{
			$defaults = array(
				'site_id' => SITE,
				'user_username' => null,
				'user_email' => null,
				'user_fullname' => null,				
			);
			$args = array_merge($defaults, $args);
			
			$cmd = $this->_db->createCommand();
			return $cmd->update('tbl_users',$args, 'user_id=:id', array(':id'=>$id));
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function updatePassword($id, $password)
	{
		try{
			$args = array(
				'user_password' => $password,			
			);			
			$cmd = $this->_db->createCommand();
			return $cmd->update('tbl_users',$args, 'user_id=:id', array(':id'=>$id));
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function validatePassword($id, $password){
		try{
			if(empty($id) || empty($password)) return false;
			
			$strSQL = " SELECT user_password, user_salt
						FROM tbl_users u
						WHERE user_id=:id";
			$cmd = $this->_db->createCommand($strSQL);
			$cmd->bindParam(":id",$id,PDO::PARAM_STR);
			$arrResults = $cmd->queryRow();
			
			if(!empty($arrResults)){
				if($arrResults['user_password'] == md5($password.$arrResults['user_salt'])) return true;
			}
			return false;
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function delete($id){
		try{
			//delete user from roles
			$cmd = $this->_db->createCommand();
			$cmd->delete('tbl_users_roles', 'user_id=:id', array(':id'=>$id));
			//delete user
			$cmd = $this->_db->createCommand();
			return $cmd->delete('tbl_users', 'user_id=:id', array(':id'=>$id));			
		} catch(Exception $ex){
			throw new Exception($ex->getMessage());
		}
	}
	
	public function getToken($user)
	{
		/* get user details if $user is id */
		if(!empty($user) && !is_array($user))
			$user = self::get($user);
		/* generate token */
		if(is_array($user) && !empty($user['user_id']) && !empty($user['user_username']) && !empty($user['user_email']) && !empty($user['user_secrectkey']))
			return base64_encode($user['user_id'].'::'.md5($user['user_id'].'::'.$user['user_username'].'::'.$user['user_email'].'::'.$user['user_secrectkey'].'::'.time()).'::'.time());	
		return '';
	}
	
	public static function validateToken($strToken, $expiration = DEFAULT_USER_TOKEN_EXPIRATION, &$decodedToken = array())
	{
		if(!empty($strToken)){
			$token = explode('::',base64_decode($strToken));
			/*check valid token*/
			if(count($token) == 3){
				$user = Application_Model_Dao_Users::getInstance()->getById($token[0]);
				/*check valid hash*/
				if(!empty($user) && $token[1] == md5($user[0]['user_id'].'::'.$user[0]['user_username'].'::'.$user[0]['user_email'].'::'.$user[0]['user_secrectkey'].'::'.$token[2])){
					/* check expiration */
					if(time() <= $token[2]+$expiration){
						$decodedToken['key']   		= $token[0];
						$decodedToken['hash'] 		= $token[1];
						$decodedToken['lifetime']   = $token[2];
						$decodedToken['object'] 	= $user[0];
						return USER_TOKEN_OK;
					}
					return USER_TOKEN_EXPIRED;
				}
			}
		}
		return USER_TOKEN_INVALID;
	}
}